package com.elitel.frame.base.service.strategy.sql;

import com.elitel.base.entity.sqlparse.InputParam;
import com.elitel.base.entity.sqlparse.SqlData;
import com.elitel.base.entity.sqlparse.SqlParser;
import com.elitel.common.utils.ParamUtils;
import com.elitel.common.utils.StringUtils;
import com.elitel.frame.main.entity.BaseQueryfield;
import com.elitel.frame.main.entity.enums.ParseSQLEnum;
import com.elitel.frame.main.entity.ext.DBServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * SQL解析策略类
 *
 * @author xqh
 * @since 2024-9-13 16:53:10
 */
@Component
@Slf4j
public class OgnlParseSQLStrategy extends ParseSQLStrategy {

    /**
     * 获取策略
     *
     * @return 策略枚举
     */
    protected ParseSQLEnum getTypeEnum() {
        return ParseSQLEnum.mybatis_ognl;
    }


    /**
     * 解析SQL查询字段
     * 本函数通过分析SQL语句提取查询字段信息，用于将SQL查询转换为特定的数据结构
     * 这是为了在系统内部更好地处理和理解SQL查询的要求
     *
     * @param server 数据库服务器信息，包含SQL查询语句
     * @return 返回一个BaseQueryfield对象列表，其中每个对象代表SQL查询中的一个参数
     */
    public List<BaseQueryfield> parseSQLQueryField(DBServer server) {
        SqlData sqlData = parseSQLGetField(server.getSql(), new HashMap<>(16));
        List<BaseQueryfield> baseQueryFields = new ArrayList<>();
        for (InputParam inputParam : sqlData.getParamList()) {
            BaseQueryfield baseQueryfield = new BaseQueryfield();
            baseQueryfield.setGuid(UUID.randomUUID().toString());
            baseQueryfield.setServiceid(server.getGuid());
            baseQueryfield.setServicetype(4);
            baseQueryfield.setShowtype(0);
            baseQueryfield.setParametercode(inputParam.getName());
            baseQueryfield.setParametervalue(inputParam.getName());
            baseQueryfield.setParamformat(inputParam.getJavaType());
            baseQueryfield.setRequiredFlag(inputParam.isRequired() ? "1" : "0");
            baseQueryFields.add(baseQueryfield);
        }
        return baseQueryFields;
    }


    /**
     * 根据sql获取sqlData包
     *
     * @param sql ognl形式sql
     * @param map 入参
     * @return
     */
    public SqlData parseSQLGetField(String sql, Map<String, String> map) {
        //入参
        Map<String, Object> params = new HashMap<>(16);
        //查询参数
        List<InputParam> paramList = new ArrayList<>();
        /**
         * 解析SQL语句，获取参数信息
         */
        List<InputParam> inputParams = ParamUtils.parseInputParam(sql);
        Set<String> ifOrWhen = parse(sql);
        Set<String> bindTag = handBindTag(sql);
        for (InputParam inputParam : inputParams) {
            //必填入参
            String inputParamName = inputParam.getName();
            if (inputParam.isRequired() || StringUtils.isNotEmpty(map.get(inputParamName))) {
                params.put(inputParamName, map.get(inputParamName));
            }
            ifOrWhen.remove(inputParamName);
            //所有入参
            if (!bindTag.contains(inputParamName)) {
                paramList.add(inputParam);
            }

        }
        ifOrWhen.forEach(param -> {
            paramList.add(new InputParam(param,null,null,true));
        });
        SqlParser sqlParser = new SqlParser();
        SqlData sqlData = sqlParser.parse(sql, params);

        sqlData.setParamList(paramList);
        return sqlData;
    }

    public Set<String> parse(String input) {
        String regex = "<if\\s+test\\s*=\\s*\"[^\"]*\">";
        Set<String> set = handIfWhenTag(input, regex);
        String regex2 = "<when\\s+test\\s*=\\s*\"[^\"]*\">";
        Set<String> set2 = handIfWhenTag(input, regex2);
        set.addAll(set2);
        return set;
    }

    private static Set<String> handIfWhenTag(String input, String regex) {
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        Set<String> set = new HashSet<>();
        while (matcher.find()) {
            String group = matcher.group();
            int first = group.indexOf("\"") + 1;
            int last = group.lastIndexOf("\"");
            String substring = group.substring(first, last);
            String tmp = "";
            if (substring.contains("==")) {
                tmp = substring.substring(0, substring.indexOf("=="));
            } else if (substring.contains("!=")) {
                tmp = substring.substring(0, substring.indexOf("!="));
            } else if (substring.contains(".size()")) {
                tmp = substring.substring(0, substring.indexOf(".size()"));
            }
            set.add(tmp.trim());
        }
        return set;
    }

    private static Set<String> handBindTag(String sql) {
        String regex = "<bind\\s+name=\"([^\"]+)\"\\s+value=\"([^\"]+)\"/>";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(sql);
        Set<String> set = new HashSet<>();
        while (matcher.find()) {
            String group = matcher.group();
            String substring = group.substring(group.indexOf('=') + 1, group.lastIndexOf("value")).trim().replace("\"","");
            set.add(substring);
        }
        return set;
    }
}
